In this tutorial we'll setup a Hidden Service with custom .onion Vanity V3 address, we'll set it up using nginx and Tor.
Before starting, check if your ISP allows tor use or not. And if it does not, make sure you install a VPN to hide the fact that you're using Tor as we did previously here:
# Download the Mullvad signing key
sudo curl -fsSLo /usr/share/keyrings/mullvad-keyring.asc https://repository.mullvad.net/deb/mullvad-keyring.asc
# Add the Mullvad repository server to apt
echo "deb [signed-by=/usr/share/keyrings/mullvad-keyring.asc arch=$( dpkg --print-architecture )] https://repository.mullvad.net/deb/stable $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/mullvad.list
# Or add the Mullvad BETA repository server to apt
echo "deb [signed-by=/usr/share/keyrings/mullvad-keyring.asc arch=$( dpkg --print-architecture )] https://repository.mullvad.net/deb/beta $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/mullvad.list
# Install the package
sudo apt update
sudo apt install mullvad-vpn
# Connect to Mullvad VPN
mullvad account login
Enter an account number: 91320912809328832
Mullvad account "91320912809328832" set
# Connect to the VPN:
mullvad lockdown-mode set on
mullvad connect
curl ifconfig.me
194.127.199.92
Once done, install tor and compute your Tor domain:
[ nowhere.moe ] [ /dev/pts/11 ] [/srv]
→ apt install gcc libc6-dev libsodium-dev make autoconf tor
[ nowhere.moe ] [ /dev/pts/11 ] [/srv]
→ git clone https://github.com/cathugger/mkp224o
Cloning into 'mkp224o'...
remote: Enumerating objects: 1571, done.
remote: Counting objects: 100% (402/402), done.
remote: Compressing objects: 100% (83/83), done.
remote: Total 1571 (delta 341), reused 350 (delta 317), pack-reused 1169
Receiving objects: 100% (1571/1571), 1.89 MiB | 6.32 MiB/s, done.
Resolving deltas: 100% (982/982), done.
[ nowhere.moe ] [ /dev/pts/11 ] [/srv]
→ cd mkp224o
[ nowhere.moe ] [ /dev/pts/11 ] [/srv/mkp224o]
→ ls
autogen.sh base64_to.c filters_common.inc.h ioutil.h test_base64.c worker.h
base16_from.c calcest.c filters.h keccak.c test_ed25519.c worker_impl.inc.h
base16.h common.h filters_inc.inc.h keccak.h testutil.h yaml.c
base16_to.c configure.ac filters_main.inc.h likely.h types.h yaml.h
base32_from.c contrib filters_worker.inc.h main.c vec.c
base32.h COPYING.txt GNUmakefile.in OPTIMISATION.txt vec.h
base32_to.c cpucount.c hex.h README.md worker_batch.inc.h
base64_from.c cpucount.h ifilter_bitsum.h test_base16.c worker_batch_pass.inc.h
base64.h ed25519 ioutil.c test_base32.c worker.c
[ nowhere.moe ] [ /dev/pts/11 ] [/srv/mkp224o]
→ ./autogen.sh
[ nowhere.moe ] [ /dev/pts/11 ] [/srv/mkp224o]
→ ./configure
checking for gcc... gcc
checking whether the C compiler works... yes
checking for C compiler default output file name... a.out
checking for suffix of executables...
checking whether we are cross compiling... no
checking for suffix of object files... o
checking whether the compiler supports GNU C... yes
checking whether gcc accepts -g... yes
checking for gcc option to enable C11 features... none needed
checking whether CC supports -march=native... yes
checking whether CC supports -fomit-frame-pointer... yes
checking whether CC supports -fPIE... yes
checking whether CC supports -std=c99... yes
checking whether CC supports -Wall... yes
checking whether CC supports -Wextra... yes
checking whether CC supports -Wno-maybe-uninitialized... yes
checking whether CC supports and needs -Wno-format -Wno-pedantic-ms-format... no
checking whether CC supports -Wno-unused-function... yes
checking whether CC supports -Wmissing-prototypes... yes
checking whether CC supports -Wstrict-prototypes... yes
checking whether ARGON2ID13 is supported by libsodium... yes
configure: creating ./config.status
config.status: creating GNUmakefile
[ nowhere.moe ] [ /dev/pts/11 ] [/srv/mkp224o]
→ make
Now i want my tor domain to contain the "datura" characters so i do the following:
[ nowhere.moe ] [ /dev/pts/11 ] [/srv/mkp224o]
→ ./mkp224o datura
sorting filters... done.
filters:
datura
in total, 1 filter
using 12 threads
daturacccspczuluj2hbgqfcpkjo75hn7bzmuzsm5zys3az6k3su45ad.onion
daturaxnp7x4ubwlslgyeaft5dabaxotmsaxanayocnpxarc7wi36kid.onion
[ nowhere.moe ] [ /dev/pts/11 ] [lib/tor/onions]
→ ls -lash
total 16K
4.0K drwx------ 4 debian-tor debian-tor 4.0K Jan 27 15:33 .
4.0K drwx--S--- 8 debian-tor debian-tor 4.0K Feb 1 15:08 ..
4.0K drwx------ 3 debian-tor debian-tor 4.0K Jul 12 2023 daturab6drmkhyeia4ch5gvfc2f3wgo6bhjrv3pz6n7kxmvoznlkq4yd.onion
4.0K drwx------ 3 debian-tor debian-tor 4.0K Jan 27 15:48 nihilhfjmj55gfbleupwl2ub7lvbhq4kkoioatiopahfqwkcnglsawyd.onion
[ nowhere.moe ] [ /dev/pts/11 ] [lib/tor/onions]
→ ls -lash daturab6drmkhyeia4ch5gvfc2f3wgo6bhjrv3pz6n7kxmvoznlkq4yd.onion
total 24K
4.0K drwx------ 3 debian-tor debian-tor 4.0K Jul 12 2023 .
4.0K drwx------ 4 debian-tor debian-tor 4.0K Jan 27 15:33 ..
4.0K drwx------ 2 debian-tor debian-tor 4.0K Jul 12 2023 authorized_clients
4.0K -r-------- 1 debian-tor debian-tor 63 Jul 12 2023 hostname
4.0K -r-------- 1 debian-tor debian-tor 64 Jul 12 2023 hs_ed25519_public_key
4.0K -r-------- 1 debian-tor debian-tor 96 Jul 12 2023 hs_ed25519_secret_key
[ nowhere.moe ] [ /dev/pts/11 ] [/srv/mkp224o]
→ cat /etc/tor/torrc
HiddenServiceDir /var/lib/tor/onions/daturab6drmkhyeia4ch5gvfc2f3wgo6bhjrv3pz6n7kxmvoznlkq4yd.onion/
HiddenServicePort 80 127.0.0.1:4443 # for web service HTTP (recommended!)
HiddenServicePort 443 127.0.0.1:4444 # for web service HTTPS (but not recommended!)
HiddenServicePort 18080 127.0.0.1:18080 # for monero nodes
HiddenServicePort 18081 127.0.0.1:18081 # for monero nodes
# to have another hidden service, you can append it afterward like so; but you need to use different ports:
HiddenServiceDir /var/lib/tor/onions/nihilhfjmj55gfbleupwl2ub7lvbhq4kkoioatiopahfqwkcnglsawyd.onion/
HiddenServicePort 80 127.0.0.1:4445
Make sure that the file permissions are correct in the /var/lib/tor/onions/datura...onion/ directory:
[ nowhere.moe ] [ /dev/pts/11 ] [lib/tor/onions]
→ chmod 700 daturab6drmkhyeia4ch5gvfc2f3wgo6bhjrv3pz6n7kxmvoznlkq4yd.onion
[ nowhere.moe ] [ /dev/pts/11 ] [lib/tor/onions]
→ chmod 400 daturab6drmkhyeia4ch5gvfc2f3wgo6bhjrv3pz6n7kxmvoznlkq4yd.onion/*
[ nowhere.moe ] [ /dev/pts/11 ] [lib/tor/onions]
→ chmod 700 daturab6drmkhyeia4ch5gvfc2f3wgo6bhjrv3pz6n7kxmvoznlkq4yd.onion/authorized_clients -R
[ nowhere.moe ] [ /dev/pts/11 ] [lib/tor/onions]
→ chown debian-tor: /var/lib/tor/onions -R
Now let's set it up on our webserver:
[ nowhere.moe ] [ /dev/pts/11 ] [~debian-tor/onions]
→ cat /etc/nginx/sites-available/nowhere.moe.conf
server {
listen 80;
listen [::]:80;
server_name nowhere.moe;
return 301 https://$server_name$request_uri;
}
server {
######## TOR CHANGES ########
listen 4443;
listen [::]:4443;
server_name daturab6drmkhyeia4ch5gvfc2f3wgo6bhjrv3pz6n7kxmvoznlkq4yd.onion;
add_header Onion-Location "http://daturab6drmkhyeia4ch5gvfc2f3wgo6bhjrv3pz6n7kxmvoznlkq4yd.onion$request_uri" always;
######## TOR CHANGES ########
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name nowhere.moe;
ssl_certificate /etc/acme/certs/nowhere.moe/fullchain.cer;
ssl_trusted_certificate /etc/acme/certs/nowhere.moe/nowhere.moe.cer;
ssl_certificate_key /etc/acme/certs/nowhere.moe/nowhere.moe.key;
[...]
root /srv/nowhere.moe/;
}
[ nowhere.moe ] [ /dev/pts/11 ] [~debian-tor/onions]
→ cat /etc/nginx/sites-available/nowhere.moe.conf
server {
listen 80;
listen [::]:80;
server_name nowhere.moe;
return 301 https://$server_name$request_uri;
}
server {
######## TOR CHANGES ########
listen 4445;
listen [::]:4445;
server_name nihilhfjmj55gfbleupwl2ub7lvbhq4kkoioatiopahfqwkcnglsawyd.onion;
add_header Onion-Location "http://nihilhfjmj55gfbleupwl2ub7lvbhq4kkoioatiopahfqwkcnglsawyd.onion$request_uri" always;
######## TOR CHANGES ########
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name nowhere.moe;
[...]
root /srv/nowhere.moe/;
ssl_certificate /etc/acme/certs/nowhere.moe/fullchain.cer;
ssl_trusted_certificate /etc/acme/certs/nowhere.moe/nowhere.moe.cer;
ssl_certificate_key /etc/acme/certs/nowhere.moe/nowhere.moe.key;
}
[ nowhere.moe ] [ /dev/pts/0 ] [tor/onions/daturab6drmkhyeia4ch5gvfc2f3wgo6bhjrv3pz6n7kxmvoznlkq4yd.onion]
→ nginx -t
2023/07/12 21:46:16 [emerg] 113983#113983: could not build server_names_hash, you should increase server_names_hash_bucket_size: 64
nginx: configuration file /etc/nginx/nginx.conf test failed
#if it gives you this error do the following:
[ nowhere.moe ] [ /dev/pts/0 ] [tor/onions/daturab6drmkhyeia4ch5gvfc2f3wgo6bhjrv3pz6n7kxmvoznlkq4yd.onion]
→ vim /etc/nginx/nginx.conf
[ nowhere.moe ] [ /dev/pts/0 ] [tor/onions/daturab6drmkhyeia4ch5gvfc2f3wgo6bhjrv3pz6n7kxmvoznlkq4yd.onion]
→ cat /etc/nginx/nginx.conf |grep 128
server_names_hash_bucket_size 128;
[ 10.0.0.101/16 ] [ /dev/pts/12 ] [/var/lib/tor]
→ nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[ 10.0.0.101/16 ] [ /dev/pts/12 ] [/var/lib/tor]
→ nginx -s reload
[ 10.0.0.101/16 ] [ /dev/pts/8 ] [~debian-tor]
→ sudo -u debian-tor tor
Jan 23 16:57:19.270 [notice] Tor 0.3.5.16 running on Linux with Libevent 2.1.8-stable, OpenSSL 1.1.1d, Zlib 1.2.11, Liblzma 5.2.4, and Libzstd 1.3.8.
Jan 23 16:57:19.270 [notice] Tor can't help you if you use it wrong! Learn how to be safe at https://www.torproject.org/download/download#warning
Jan 23 16:57:19.270 [notice] Read configuration file "/etc/tor/torrc".
Jan 23 16:57:19.278 [notice] Opening Socks listener on 127.0.0.1:9050
Jan 23 16:57:19.278 [notice] Opened Socks listener on 127.0.0.1:9050
Jan 23 16:57:19.000 [notice] Parsing GEOIP IPv4 file /usr/share/tor/geoip.
Jan 23 16:57:19.000 [notice] Parsing GEOIP IPv6 file /usr/share/tor/geoip6.
Jan 23 16:57:19.000 [warn] You are running Tor as root. You don't need to, and you probably shouldn't.
Jan 23 16:57:19.000 [notice] Bootstrapped 0%: Starting
Jan 23 16:57:20.000 [notice] Starting with guard context "default"
Jan 23 16:57:20.000 [notice] Bootstrapped 10%: Finishing handshake with directory server
Jan 23 16:57:20.000 [notice] Bootstrapped 80%: Connecting to the Tor network
Jan 23 16:57:20.000 [notice] Bootstrapped 90%: Establishing a Tor circuit
Jan 23 16:57:21.000 [notice] Bootstrapped 100%: Done
From there we can check if our tor website is up:
It works! Now let's use systemctl to start tor instead:
[ nowhere.moe ] [ /dev/pts/11 ] [~debian-tor/onions]
→ systemctl restart tor@default
[ nowhere.moe ] [ /dev/pts/11 ] [~debian-tor/onions]
→ systemctl status tor@default
● tor@default.service - Anonymizing overlay network for TCP
Loaded: loaded (/lib/systemd/system/tor@default.service; enabled-runtime; preset: enabled)
Active: active (running) since Thu 2024-02-01 15:24:07 CET; 18min ago
Process: 3027334 ExecStartPre=/usr/bin/install -Z -m 02755 -o debian-tor -g debian-tor -d /run/tor (code=exited, status=0/SUCCESS)
Process: 3027335 ExecStartPre=/usr/bin/tor --defaults-torrc /usr/share/tor/tor-service-defaults-torrc -f /etc/tor/torrc --RunAsDaemon 0 --verify-config (code=exited, status=0/SUCCESS)
Main PID: 3027336 (tor)
Tasks: 30 (limit: 77000)
Memory: 636.4M
CPU: 49.885s
CGroup: /system.slice/system-tor.slice/tor@default.service
├─3027336 /usr/bin/tor --defaults-torrc /usr/share/tor/tor-service-defaults-torrc -f /etc/tor/torrc --RunAsDaemon 0
└─3027337 /usr/bin/obfs4proxy
Feb 01 15:24:26 nowhere.moe Tor[3027336]: Your network connection speed appears to have changed. Resetting timeout to 60000ms after 18 timeouts and 1000 buildtimes.
Feb 01 15:25:09 nowhere.moe Tor[3027336]: Performing bandwidth self-test...done.
Now we can do the same for a subdomain:
[ nowhere.moe ] [ /dev/pts/11 ] [/etc/nginx/sites-available]
→ cat cringe.nowhere.moe.conf
server {
listen 443 ssl;
server_name cringe.nowhere.moe;
ssl_certificate /etc/acme/certs/cringe.nowhere.moe/cringe.nowhere.moe.cer;
ssl_certificate_key /etc/acme/certs/cringe.nowhere.moe/cringe.nowhere.moe.key;
######## TOR CHANGES ########
listen 4443;
listen [::]:4443;
server_name cringe.daturab6drmkhyeia4ch5gvfc2f3wgo6bhjrv3pz6n7kxmvoznlkq4yd.onion;
add_header Onion-Location "http://cringe.daturab6drmkhyeia4ch5gvfc2f3wgo6bhjrv3pz6n7kxmvoznlkq4yd.onion$request_uri" always;
######## TOR CHANGES ########
[...]
location / {
proxy_pass http://localhost:8083;
}
location = /robots.txt {
add_header Content-Type text/plain;
return 200 "User-agent: *\nDisallow: /\n";
}
}
[ nowhere.moe ] [ /dev/pts/11 ] [/etc/nginx/sites-available]
→ nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[ nowhere.moe ] [ /dev/pts/11 ] [/etc/nginx/sites-available]
→ nginx -s reload
2024/02/01 15:45:18 [notice] 3045373#3045373: signal process started
Now that we have our website up and running, it's better to configure some DoS countermeasures to avoid any unpleasant problems.
There are many countermeasures, one of the most effective is PoW. If you want to learn more about other DoS prevention methods check the guidelines. If you want to learn more about how PoW works, check out the FAQs.
Without further ado, let's enable PoW for our onion service.
Add the following to your /etc/tor/torrc
HiddenServicePoWDefensesEnabled 1
HiddenServicePoWQueueRate 250
HiddenServicePoWQueueBurst 2500
This is what the options do (taken from tor(1)
manual)
HiddenServicePoWDefensesEnabled 0|1
Enable proof-of-work based service DoS mitigation. If set to 1
(enabled), tor will include parameters for an optional client
puzzle in the encrypted portion of this hidden service’s
descriptor. Incoming rendezvous requests will be prioritized based
on the amount of effort a client chooses to make when computing a
solution to the puzzle. The service will periodically update a
suggested amount of effort, based on attack load, and disable the
puzzle entirely when the service is not overloaded. (Default: 0)
HiddenServicePoWQueueRate NUM
The sustained rate of rendezvous requests to dispatch per second
from the priority queue. Has no effect when proof-of-work is
disabled. If this is set to 0 there’s no explicit limit and we will
process requests as quickly as possible. (Default: 250)
HiddenServicePoWQueueBurst NUM
The maximum burst size for rendezvous requests handled from the
priority queue at once. (Default: 2500)
If you don't know what rendezvous requests are, check out the specification, but essentially see them as "Hello I am NODE_X, I want to connect to NODE_Y to create a circuit, can you let me do it?"
If you are wondering how the priority queue is managed, think of it as how much effort the client put into solving the challenge; the more effort the higher the client priority will be (but also the time took to solve the challenge)
Don't forget to restart the hidden service to enable the changes made.
Donate XMR: 8AUYjhQeG3D5aodJDtqG499N5jXXM71gYKD8LgSsFB9BUV1o7muLv3DXHoydRTK4SZaaUBq4EAUqpZHLrX2VZLH71Jrd9k8
Contact: nihilist@contact.nowhere.moe (PGP)